package cn.dakaqi.apps.group.rsa;

import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 加解签算法
 *
 * @author
 */
public class RSASignature {

	private static final String KEY_ALGORITHM = "RSA";

	private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";

	private static final String SIGNATURE_ALGORITHM_LU = "SHA256withRSA";

	private static final int KEYSIZE = 1024;

	/**
	 * Gen key.
	 * 生成RSA公私密钥对 （byteToHexString 转成十六进制字符串）
	 * @throws Exception the exception
	 */
	public static void genKey() throws Exception {

		KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		SecureRandom random = new SecureRandom();
		keygen.initialize(KEYSIZE, random);
		// 取得密钥对
		KeyPair kp = keygen.generateKeyPair();
		RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
		String privateKeyString = byteToHexString(privateKey.getEncoded());
		System.out.println("PRIVATE_KEY:");
		System.out.println(privateKeyString);

		RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
		String publicKeyString = byteToHexString(publicKey.getEncoded());
		System.out.println("PUBLIC_KEY:");
		System.out.println(publicKeyString);
	}

	/**
	 * 加签数据
	 *
	 * @param data       待加签数据
	 * @param privateKey 私钥
	 * @return String signedData 加签值（十六进制）
	 * @throws Exception the exception
	 */
	public static String sign(String data, String privateKey) throws Exception {
		try {
			byte[] signData = sign(data, hexStringToByte(privateKey));

			return byteToHexString(signData);

		} catch (Exception e) {
			throw new Exception("signature.sign.error : " + e.getMessage());
		}
	}

	/**
	 * Sign for lu string.
	 *
	 * @param data       the data
	 * @param privateKey the private key
	 * @return the string
	 * @throws Exception the exception
	 */
	public static String signForLu(String data, String privateKey)
			throws Exception {
		try {
			byte[] signData = signForLu(data, hexStringToByte(privateKey));

			return byteToHexString(signData);

		} catch (Exception e) {
			throw new Exception("signature.sign.error : " + e.getMessage());
		}
	}

	/**
	 * 加签数据
	 *
	 * @param data            待加签数据
	 * @param privateKeyBytes the private key bytes
	 * @return byte[] signedData
	 * @throws Exception the exception
	 */
	public static byte[] sign(String data, byte[] privateKeyBytes)
			throws Exception {

		try {
			PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
					privateKeyBytes);
			KeyFactory keyf = KeyFactory.getInstance(KEY_ALGORITHM);
			PrivateKey key = keyf.generatePrivate(priPKCS8);

			// 进行签名服务
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			signature.initSign(key);
			signature.update(data.getBytes());
			byte[] signData = signature.sign();

			// 返回签名结果
			return signData;
		} catch (Exception e) {
			throw new Exception("signature.sign.error : " + e.getMessage());
		}
	}

	/**
	 * Sign for lu byte [ ].
	 *
	 * @param data            the data
	 * @param privateKeyBytes the private key bytes
	 * @return the byte [ ]
	 * @throws Exception the exception
	 */
	public static byte[] signForLu(String data, byte[] privateKeyBytes)
			throws Exception {

		try {
			PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
					privateKeyBytes);
			KeyFactory keyf = KeyFactory.getInstance(KEY_ALGORITHM);
			PrivateKey key = keyf.generatePrivate(priPKCS8);

			// 进行签名服务
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM_LU);
			signature.initSign(key);
			signature.update(data.getBytes());
			byte[] signData = signature.sign();

			// 返回签名结果
			return signData;
		} catch (Exception e) {
			throw new Exception("signature.sign.error : " + e.getMessage());
		}
	}

	/**
	 * 根据对签名数据使用签名者的公钥来解密后验证是否与原数据相同。从而确认用户签名正确
	 *
	 * @param data      the data
	 * @param signStr   the sign str
	 * @param publicKey the public key
	 * @return true或false ，验证成功为true。
	 * @throws Exception the exception
	 */
	public static boolean verify(String data, String signStr, String publicKey)
			throws Exception {
		try {
			return verify(data, hexStringToByte(signStr),
					hexStringToByte(publicKey));
		} catch (Exception e) {
			throw new Exception("signature.verify.error : " + e.getMessage());
		}
	}

	/**
	 * 根据对签名数据使用签名者的公钥来解密后验证是否与原数据相同。从而确认用户签名正确
	 *
	 * @param data           the data
	 * @param signStrBytes   the sign str bytes
	 * @param publicKeyBytes the public key bytes
	 * @return true或false ，验证成功为true。
	 * @throws Exception the exception
	 */
	public static boolean verify(String data, byte[] signStrBytes,
								 byte[] publicKeyBytes) throws Exception {
		try {
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			PublicKey pubKey = keyFactory
					.generatePublic(new X509EncodedKeySpec(publicKeyBytes));

			// 进行验证签名服务
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			signature.initVerify(pubKey);
			signature.update(data.getBytes());
			return signature.verify(signStrBytes);
		} catch (Exception e) {
			throw new Exception("signature.verify.error : " + e.getMessage());
		}
	}

	/**
	 * Verify for lu boolean.
	 *
	 * @param data      the data
	 * @param signStr   the sign str
	 * @param publicKey the public key
	 * @return the boolean
	 * @throws Exception the exception
	 */
	public static boolean verifyForLu(String data, String signStr,
									  String publicKey) throws Exception {
		try {
			return verifyForLu(data, hexStringToByte(signStr),
					hexStringToByte(publicKey));
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * Verify for lu boolean.
	 *
	 * @param data           the data
	 * @param signStrBytes   the sign str bytes
	 * @param publicKeyBytes the public key bytes
	 * @return the boolean
	 * @throws Exception the exception
	 */
	public static boolean verifyForLu(String data, byte[] signStrBytes,
									  byte[] publicKeyBytes) throws Exception {
		try {
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			PublicKey pubKey = keyFactory
					.generatePublic(new X509EncodedKeySpec(publicKeyBytes));

			// 进行验证签名服务
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM_LU);
			signature.initVerify(pubKey);
			signature.update(data.getBytes());
			return signature.verify(signStrBytes);
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 二进制byte[]转十六进制string
	 *
	 * @param bytes the bytes
	 * @return the string
	 */
	public static String byteToHexString(byte[] bytes) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			String strHex = Integer.toHexString(bytes[i]);
			if (strHex.length() > 3) {
				sb.append(strHex.substring(6));
			} else {
				if (strHex.length() < 2) {
					sb.append("0" + strHex);
				} else {
					sb.append(strHex);
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 十六进制string转二进制byte[]
	 *
	 * @param s the s
	 * @return the byte [ ]
	 * @throws Exception the exception
	 */
	public static byte[] hexStringToByte(String s) throws Exception {
		byte[] baKeyword = new byte[s.length() / 2];
		for (int i = 0; i < baKeyword.length; i++) {
			try {
				baKeyword[i] = (byte) (0xff & Integer.parseInt(
						s.substring(i * 2, i * 2 + 2), 16));
			} catch (Exception e) {
				System.out.println("十六进制转byte发生错误！！！");
				throw (e);
			}
		}
		return baKeyword;
	}

	/**
	 * The entry point of application.
	 *
	 * @param args the input arguments
	 * @throws Exception the exception
	 */
	public static void main(String[] args) throws Exception {
		try {
			 genKey();
			//String PRIVATE_KEY = "30820276020100300d06092a864886f70d0101010500048202603082025c020100028181009b7ff7acade0eec996c7c6755590ea7698e5050241918664115e251679347ccfc58064d725f42a86df4e7ce450e44cb65e804220e137d925b2813a5b30379e84ce63097d1b568edc81a930c5d1c6262950591b037954ebb7d6817529062c86a82b7adf5d6e67dbdef6050096038316ec8296be4bb733b463884b732ac12ad4bb02030100010281803f797d207fd9d19f786d1415d157d65d930be97f8244651773ff7a243255ba9d1581d3a7ff562c05e221a7d98b2ba624cb6e8f8fdc5f6fc473994cb8ec75c7becb946e23688ed7011399cc1b3baf580d367d45fa82c1f2140b1846f6c0631859cee969591079936f83f9fd6ce839deb8c5ad995b85e18ed499c33cfbb2049801024100cba08a16648262af8b25779062b0ef30d6085ddbe19bf62d9e0629a5c7b28b23773e8a2e8db1ca6636ffd73751738f70a49beaaa8a77f25a44179ff627f890b3024100c37e93b09a2cfb073246c9d97e4aebac65645eeae0a304a3f85d1cd2ca7a5bb37c7909d44bb5b97fdf1512565f9f62dd825be85d81e3fb165a05aca1c6839fd902403c644fb0167d2921a1262a90d30460dc5e0e3b3014787a09cb7d4e6ad1905d7dd646e11aaf819462be5b208c5286f07adb073710ff6255a979da7be1b8b71acb02402e3dec956382ac4641803912b72ae5a03bc388282ac6a4bc5c6d39fa2a66d2f61bc54dabe7d4ae722ec47f37eb1a7a7a46f1927f3bd03f7e4400ff9aaca849d102410089025c6d4a5c8ece1ca5140a98a1e85e21550c6fba92b0314b9ce07e749a1242f0c99f86a9124f16b20a89fd3b35cbc609e45a9befd12c13b1a6d971e7b927dd";
			//String PUBLIC_KEY = "30819f300d06092a864886f70d010101050003818d00308189028181009b7ff7acade0eec996c7c6755590ea7698e5050241918664115e251679347ccfc58064d725f42a86df4e7ce450e44cb65e804220e137d925b2813a5b30379e84ce63097d1b568edc81a930c5d1c6262950591b037954ebb7d6817529062c86a82b7adf5d6e67dbdef6050096038316ec8296be4bb733b463884b732ac12ad4bb0203010001";
			//String data = "上海陆家嘴国际金融资产交易市场股份有限公司";
			//System.out.println(verify(data, sign(data, PRIVATE_KEY), PUBLIC_KEY));
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}
